﻿using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using UnityDemo.Models;

//http://www.codeproject.com/Tips/322695/Unity-2-0-Interception-via-Method-Decoration-in-ve

namespace UnityDemo.InjectionCode
{
    public class InterceptionDemo : BaseFeatureDemo
    {
        public InterceptionDemo()
        {
            var unityContainer = new UnityContainer();

            //This allows Interception for the whole Unity container.
            unityContainer.AddNewExtension<Interception>();

            //This sets up an InterfaceInterceptor for IAuthenticationService
            //IAuthenticationService is a class I wrote (see below), simply substitute
            //whatever class you're interested in intercepting here
            unityContainer.Configure<Interception>()
                .SetInterceptorFor<IAuthentication>(new InterfaceInterceptor());
        }

        //define what it is you want to do with your custom interceptor

        protected override void RegisterSamples()
        {
            throw new NotImplementedException();
        }

        #region Nested type: IAuthentication

        public interface IAuthentication
        {
            [LogExceptions]
            bool isAuthenticated(string userName, string password);
        }

        #endregion

        #region Nested type: LogExceptionsAttribute

        public class LogExceptionsAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new LogExceptionsHandler();
            }
        }

        #endregion

        #region Nested type: LogExceptionsHandler

        public class LogExceptionsHandler : ICallHandler
        {
            #region ICallHandler Members

            public int Order { get; set; }

            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                //Put any logic here you would like to invoke BEFORE the method is invoked.
                Console.WriteLine("Before method Invocation happened");

                //This invokes the next item in the Injection pipeline, or eventually
                //calls your method
                IMethodReturn methodReturn = getNext().Invoke(input, getNext);

                // AFTER the target method execution check to see if it excepted
                if (methodReturn.Exception != null)
                {
                    Console.WriteLine("Add some real logging here");
                }

                    //if you would like to re-throw, do it here, otherwise just return
                    //your methodReturn
                else
                {
                    Console.WriteLine
                        ("To Rethrow, or not to rethrow, that is the question.");
                }
                return methodReturn;
            }

            #endregion
        }

        #endregion
    }
}